package cn.virens.web.components.open.wxmp.router.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import cn.hutool.core.util.StrUtil;
import cn.virens.common.StringUtil;
import cn.virens.database.common.TransactionExecute;
import cn.virens.database.enums.UserType;
import cn.virens.database.mysql.model.sys.SysUser;
import cn.virens.database.mysql.model.sys.SysUserBind;
import cn.virens.exception.APIException;
import cn.virens.service.inter.sys.SysUserService;
import cn.virens.service.inter.sys.user.SysUserGroupRelationService;
import cn.virens.service.inter.sys.user.SysUserRoleRelationService;
import cn.virens.web.components.open.session.WxSession;
import cn.virens.web.components.open.session.WxSessionManager;
import cn.virens.web.components.open.wxmp.annotations.WxMpRouterRule;
import cn.virens.web.components.open.wxmp.session.WxMpSessionMessage;
import cn.virens.web.components.shiro.ShiroAuthInterface;
import cn.virens.web.components.shiro.token.ChannelResult;
import cn.virens.web.components.shiro.token.ChannelTokenSimple;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;

@Component
@WxMpRouterRule(async = false, contentRegex = "绑定:.*", reEnter = true)
public class WxMpMessageBindHandler extends AbstractMessageHandler {
	private static final String BIND_KEY_0 = "bind-account";
	private static final String BIND_KEY_1 = "bind-uuid";
	private static final String BIND_KEY_2 = "bind-pwd";

	private @Autowired TransactionExecute mTransactionExecute;
	private @Autowired SysUserService mSysUserService;
	private @Autowired ShiroAuthInterface mShiroAuthInterface;
	private @Autowired SysUserRoleRelationService mSysUserRoleRelationService;
	private @Autowired SysUserGroupRelationService mSysUserGroupRelationService;

	@Value("${weixin.cfg.mp.val.role}")
	private String defaultRoleValue;

	@Value("${weixin.cfg.mp.val.group}")
	private String defaultGroupValue;

	@Override
	protected WxMpXmlOutMessage handle0(WxMpSessionMessage message, WxSessionManager manager) throws Exception {
		return mTransactionExecute.write((s) -> {
			// 验证输入内容 & 并从中获取有效数据部分
			String content = message.getContent();
			if (content == null || content.length() <= 3) {//
				return text(message, "输入不合法");
			} else {
				content = content.substring(3);
			}

			// 检查当前微信是否已经绑定过用户---------------------------------------------------------------------------------
			if (bindCheck(UserType.WEIXIN, message.getFromUser())) {//
				return text(message, "已绑定账号");
			}

			// 如果用户发送的消息是“绑定:创建”的消息内容------------------------------------------------------------------------
			if (content != null && StrUtil.equals(content, "创建")) {
				WxMpUser mpUser = getUserinfo(message.getFromUser());
				if (mpUser == null) return text(message, "获取用户信息失败");

				SysUser user = new SysUser();
				user.setName(mpUser.getNickname());
				user.setAvatar(mpUser.getHeadImgUrl());

				SysUserBind record = new SysUserBind();
				record.setType(UserType.WEIXIN.getKey());
				record.setAccount(mpUser.getOpenId());
				record.setPasswordSrc("123456");

				if (mSysUserService.insert(user, record) != null) {
					this.bindUnionID(mpUser, record);
					this.bindUserRole(user);

					return text(message, "创建成功:" + user.getName());
				} else {
					return text(message, "创建失败");
				}
			}

			// 如果用户发送的消息是“绑定:账号”的消息内容------------------------------------------------------------------------
			WxSession session = message.getSession(manager);

			// 验证用户是否已经将账号发送过来
			Object pwd = session.getAttribute(BIND_KEY_2);
			Object uuid = session.getAttribute(BIND_KEY_1);
			Object account = session.getAttribute(BIND_KEY_0);
			if (account == null || uuid == null || pwd == null) {
				ChannelResult result = mShiroAuthInterface.getUserToken(new ChannelTokenSimple(content));
				if (!ChannelResult.vaild(result)) return text(message, "用户不存在，如果要创建请回复\"绑定:创建\"");

				session.setAttribute(BIND_KEY_2, result.getPassword());
				session.setAttribute(BIND_KEY_1, result.getUuid());
				session.setAttribute(BIND_KEY_0, content);

				return text(message, "请输入 \"绑定:\" + 密码 完成用户绑定");
			}

			// 如果用户发送的消息是“绑定:密码”的消息内容------------------------------------------------------------------------
			String password = StringUtil.md5(content);
			if (!StrUtil.equals(password, pwd.toString())) {//
				return text(message, "密码不正确，请重新输入");
			}

			WxMpUser mpUser = getUserinfo(message.getFromUser());
			if (mpUser == null) return text(message, "获取用户信息失败");

			// 创建用户绑定实例
			SysUserBind record = new SysUserBind();
			record.setType(UserType.WEIXIN.getKey());
			record.setAccount(mpUser.getOpenId());
			record.setUuid(uuid.toString());
			record.setPassword(password);

			// 完成用户绑定
			if (mSysUserService.bindCreate(record) != null) {
				this.bindUnionID(mpUser, record);

				return text(message, "绑定成功");
			} else {
				return text(message, "绑定失败");
			}
		});
	}

	private WxMpUser getUserinfo(String openid) throws WxErrorException {
		return getUserService().userInfo(openid);
	}

	/** 检查对应的账号是否已经绑定用户 */
	private boolean bindCheck(UserType type, String account) {
		return mSysUserService.bindCheck(type, account) != null;
	}

	private void bindUserRole(SysUser user) {
		JSONArray array1 = JSON.parseArray(defaultRoleValue);
		JSONArray array2 = JSON.parseArray(defaultGroupValue);

		mSysUserRoleRelationService.putRoleList(user.getUuid(), array1);
		mSysUserGroupRelationService.putGroupList(user.getUuid(), array2);
	}

	/** 判断uninonid 是否存在，如果存在需要将unionid也绑定到当前账号 */
	private void bindUnionID(WxMpUser mpUser, SysUserBind record) {
		if (StrUtil.isEmpty(mpUser.getUnionId())) return;

		if (!bindCheck(UserType.WEIXIN_2, mpUser.getUnionId())) {//
			SysUserBind record1 = new SysUserBind();
			record1.setType(UserType.WEIXIN_2.getKey());
			record1.setPassword(record.getPassword());
			record1.setAccount(mpUser.getUnionId());
			record1.setUuid(record.getUuid());

			if (mSysUserService.bindCreate(record1) == null) {//
				throw new APIException("BIND_ERR", "创建失败");
			}
		}
	}
}
